﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Blackbird.Common.Exceptions;
using Blackbird.Common.Properties;
using Blackbird.Common.Utility;
using Blackbird.Core.Editable.Base;

namespace Blackbird.Core.Editable.Frames
{
    public class EditableFramesetList : EditableEntityCollection<EditableFrameset>
    {
        /// <summary>
        /// Searches for a given frameset by name.
        /// </summary>
        /// <param name="name">The name of the frameset to search for.</param>
        /// <returns>The first frameset that matches the name given.</returns>
        /// <exception cref="Blackbird.Common.Exceptions.InvalidFramesetException">Throws if no frameset exists that matches the name given.</exception>
        public EditableFrameset this[string name]
        {
            get
            {
                EditableFrameset frameset = Find(fs => fs.Name == name);
                if (frameset != null)
                {
                    return frameset;
                }
                InvalidFramesetException.Throw();

                // Unreachable, but required because the compiler can't figure out the Exception.Throw() device above.
                return null;
            }
        }

        /// <summary>
        /// Returns a list of names of the framesets in the list.
        /// </summary>
        public List<string> FramesetNames
        {
            get { return this.Select(fs => fs.Name).ToList(); }
        }

        /// <summary>
        /// Determines if the list contains the item by name.
        /// </summary>
        /// <param name="name">The name of the EditableFrameset to search for.</param>
        /// <returns>True if the EditableFramesetList contains one or more framesets with the given name.</returns>
        public bool Contains(string name)
        {
            return (Find(fs => fs.Name == name) != null);
        }

        /// <summary>
        /// Finds the first index of the item matching the provided predicate.
        /// </summary>
        /// <param name="match">The predicate function to use when evaluating framesets.</param>
        /// <returns>The first index of the matching frameset, or -1 if no match exists.</returns>
        public int IndexOf(Predicate<EditableFrameset> match)
        {
            for (int idx = 0; idx < Count; idx++)
                if (match(this[idx]))
                    return idx;
            return -1;
        }

        /// <summary>
        /// Finds the first EditableFrameset instance in the collection that matches the predicate provided.
        /// </summary>
        /// <param name="match">The predicate function to use when evaluating the frameset.</param>
        /// <returns>The first EditableFrameset in the collection that meets the predicate, or null if none match.</returns>
        public EditableFrameset Find(Func<EditableFrameset, bool> match)
        {
            return this.FirstOrDefault(match);
        }

        protected override void ReadXmlContent(XmlReader reader)
        {
            Name = SerializationUtility.ReadElement(reader, "name", "name");
            reader.ReadStartElement("framesets");
            while (reader.NodeType != XmlNodeType.EndElement)
            {
                var frameset = new EditableFrameset();
                frameset.ReadXml(reader);
                Add(frameset);
                reader.Read();
            }
            reader.ReadEndElement();
        }

        protected override void WriteXmlContent(XmlWriter writer)
        {
            writer.WriteElementString("name", Name);
            writer.WriteStartElement("framesets");
            foreach (EditableFrameset frameset in this)
                frameset.WriteXml(writer);
            writer.WriteEndElement();
        }

        public override string TypeName
        {
            get { return Resources.EditableFramesetListTypeFriendlyName; }
        }

        protected override void ReadXmlAttributes(XmlReader reader)
        {
        }

        protected override void WriteXmlAttributes(XmlWriter writer)
        {
        }
    }
}